#ifndef MATRIX4_H
#define MATRIX4_H

#include "Framework/Prerequisites.h"
#include "Math/Math.h"

#include "Math/Vector3.h"
#include "Math/Vector4.h"
#include "Math/Quaternion.h"
#include "Math/Matrix3.h"

namespace tyro
{
	namespace Math
	{

		template < class T >
		class Matrix4
		{

		public:

			/* Matrix 4 data members */
			union
			{
				T			m[ 4 ][ 4 ];
				T			mat[ 16 ];
				struct
				{
					T		m00, m01, m02, m03;
					T		m10, m11, m12, m13;
					T		m20, m21, m22, m23;
					T		m30, m31, m32, m33;
				};
			};

			/* Constructors */
								Matrix4<T>(){}
			inline 				Matrix4<T>( const T* mat ); 
			inline				Matrix4<T>( T _00, T _01, T _02, T _03,
											T _10, T _11, T _12, T _13,
											T _20, T _21, T _22, T _23,
											T _30, T _31, T _32, T _33 );
			inline				Matrix4<T>( const Matrix3<T>& mat );					   
			inline				Matrix4<T>( const Matrix4<T>& mat );


			/* Operator Overloaders */

			/* Casting Operators*/
			inline 				operator T* ();
			inline 				operator const T* () const;

			/* Access Operators */
			inline T&			operator () ( unsigned int row, unsigned int column );
			inline T			operator () ( unsigned int row, unsigned int column ) const;

			/* Assignment Operators */

			/* Relational and Equality Operators */
			inline bool			operator == ( const Matrix4<T>& mat ) const;
			inline bool			operator != ( const Matrix4<T>& mat ) const;

			/* Binary Arithmetic Operators */
			inline const Matrix4<T> operator - () const;
			inline const Matrix4<T> operator + ( const Matrix3<T>& mat ) const;
			inline const Matrix4<T> operator + ( const Matrix4<T>& mat ) const;
			inline const Matrix4<T> operator - ( const Matrix3<T>& mat ) const;
			inline const Matrix4<T> operator - ( const Matrix4<T>& mat ) const;
			inline const Matrix4<T> operator * ( T value ) const;
			inline const Matrix4<T> operator * ( const Matrix3<T>& mat ) const;
			inline const Matrix4<T> operator * ( const Matrix4<T>& mat ) const;


			
			//-----------------------------------------------------------------------------
			// Friend multiply row value by matrix operator. 
			//-----------------------------------------------------------------------------
			inline friend const Matrix4<T> operator * ( T value, const Matrix4<T>& mat )
			{
				return mat * value;
			}
			
			//-----------------------------------------------------------------------------
			// Friend multiply row Vector3 by matrix operator. W is assumed to be 1
			//-----------------------------------------------------------------------------
			inline friend const Vector3<T> operator * ( const Vector3<T>& vec, const Matrix4<T>& mat )
			{
				Vector3<T> ans;
				ans.x = vec.x * mat.m00 + vec.y * mat.m10 + vec.z * mat.m20 + mat.m30;
				ans.y = vec.x * mat.m01 + vec.y * mat.m11 + vec.z * mat.m21 + mat.m31;
				ans.z = vec.x * mat.m02 + vec.y * mat.m12 + vec.z * mat.m22 + mat.m32;
				return ans;
			}

			//-----------------------------------------------------------------------------
			// Friend multiply row Vector4 by matrix operator.
			//-----------------------------------------------------------------------------
			inline friend const Vector4<T> operator * ( const Vector4<T>& vec, const Matrix4<T>& mat )
			{
				Vector4<T> ans;
				ans.x = vec.x * mat.m00 + vec.y * mat.m10 + vec.z * mat.m20 + vec.w * mat.m30;
				ans.y = vec.x * mat.m01 + vec.y * mat.m11 + vec.z * mat.m21 + vec.w * mat.m31;
				ans.z = vec.x * mat.m02 + vec.y * mat.m12 + vec.z * mat.m22 + vec.w * mat.m32;
				ans.w = vec.x * mat.m03 + vec.y * mat.m13 + vec.z * mat.m23 + vec.w * mat.m33;
				return ans;
			}

			

			/* Compound Assignment Operators */
			inline Matrix4<T>&		operator += ( const Matrix3<T>& mat );
			inline Matrix4<T>&		operator += ( const Matrix4<T>& mat );
			inline Matrix4<T>&		operator -= ( const Matrix3<T>& mat );
			inline Matrix4<T>&		operator -= ( const Matrix4<T>& mat );
			inline Matrix4<T>&		operator *= ( T value );
			inline Matrix4<T>&		operator *= ( const Matrix3<T>& mat );
			inline Matrix4<T>&		operator *= ( const Matrix4<T>& mat );


			inline void Add( const Matrix4<T>& matA, const Matrix4<T>& matB );
			inline void Subtract( const Matrix4<T>& matA, const Matrix4<T>& matB );
			inline void	Multiply( const Matrix4<T>& matA, const Matrix4<T>& matB );

			
			inline void  		RotateX( T angle );
			inline void  		RotateY( T angle );
			inline void  		RotateZ( T angle );
			inline void			RotateZXY( const Vector3<T>& angles );
			inline void			RotateZXYTranslation( const Vector3<T>& angles, const Vector3<T>& vec );
			inline void			Scale( const Vector3<T>& vec );
			inline void			Scale( T value );
			inline void			Translate( const Vector3<T>& vec );
			inline void			Transpose();
			inline Matrix4<T>   GetTranspose() const;
			inline void		    MakeTransform(const Math::Vector3<T> translation, const Math::Vector3<T> scale, const Math::Quaternion<T> rotation);

			inline void			SetTranslation( const Vector3<T>& vec );


			

			/* Constants */
			static const Matrix4<T> ZERO;
			static const Matrix4<T> IDENTITY;

		};

		template < class T >
		void tyro::Math::Matrix4<T>::MakeTransform( const Math::Vector3<T> translation, const Math::Vector3<T> scale, const Math::Quaternion<T> rotation )
		{
			Matrix3<T> rot3x3;
			rotation.ToRotationMatix(rot3x3);

			// Set up final matrix with scale, rotation and translation
			m[0][0] = scale.x * rot3x3.m00; m[0][1] = scale.y * rot3x3.m01; m[0][2] = scale.z * rot3x3.m02; m[0][3] = translation.x;
			m[1][0] = scale.x * rot3x3.m10; m[1][1] = scale.y * rot3x3.m11; m[1][2] = scale.z * rot3x3.m12; m[1][3] = translation.y;
			m[2][0] = scale.x * rot3x3.m20; m[2][1] = scale.y * rot3x3.m21; m[2][2] = scale.z * rot3x3.m22; m[2][3] = translation.z;

			// No projection term
			m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
		}

		template < class T >
		inline void Matrix4<T>::SetTranslation( const Vector3<T>& vec )
		{
			m30 = vec.x; m31 = vec.y; m32 = vec.z;
		}

		//-----------------------------------------------------------------------------
		// Constructor
		//-----------------------------------------------------------------------------
		template < class T >
		inline tyro::Math::Matrix4<T>::Matrix4( const Matrix3<T>& mat )
		{
			( *this ).m00 = mat.m00; ( *this ).m01 = mat.m01; ( *this ).m02 = mat.m02; ( *this ).m03 = 0.0f;
			( *this ).m10 = mat.m10; ( *this ).m11 = mat.m11; ( *this ).m12 = mat.m12; ( *this ).m13 = 0.0f;
			( *this ).m20 = mat.m20; ( *this ).m21 = mat.m21; ( *this ).m22 = mat.m22; ( *this ).m23 = 0.0f;
			( *this ).m30 = 0.0f; ( *this ).m31 = 0.0f; ( *this ).m32 = 0.0f; ( *this ).m33 = 1.0f;
		}
		
		template < class T >
		inline tyro::Math::Matrix4<T>::Matrix4( const T* mat ) 
		{
			memcpy( this->mat, mat, sizeof( this->mat ) );
		}

		//-----------------------------------------------------------------------------
		// Constructor
		//-----------------------------------------------------------------------------
		template < class T >
		inline	tyro::Math::Matrix4<T>::Matrix4( T _00, T _01, T _02, T _03,
			T _10, T _11, T _12, T _13,
			T _20, T _21, T _22, T _23,
			T _30, T _31, T _32, T _33 )
		{
			( *this ).mat[ 0 ] = _00; ( *this ).mat[ 1 ] = _01; ( *this ).mat[ 2 ] = _02; ( *this ).mat[ 3 ] = _03;
			( *this ).mat[ 4 ] = _10; ( *this ).mat[ 5 ] = _11; ( *this ).mat[ 6 ] = _12; ( *this ).mat[ 7 ] = _13;
			( *this ).mat[ 8 ] = _20; ( *this ).mat[ 9 ] = _21; ( *this ).mat[ 10 ] = _22; ( *this ).mat[ 11 ] = _23;
			( *this ).mat[ 12 ] = _30; ( *this ).mat[ 13 ] = _31; ( *this ).mat[ 14 ] = _32; ( *this ).mat[ 15 ] = _33;
		}
		//-----------------------------------------------------------------------------
		// Constructor
		//-----------------------------------------------------------------------------
		template < class T >
		inline tyro::Math::Matrix4<T>::Matrix4( const Matrix4& mat )
		{
			memcpy( this, &mat, sizeof( Matrix4<T> ) );
		}

		//-----------------------------------------------------------------------------
		// Casting operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline Matrix4<T>::operator T*()
		{
			return reinterpret_cast<T*>(this);
		}

		//-----------------------------------------------------------------------------
		// Const casting operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline Matrix4<T>::operator const T*() const
		{
			return reinterpret_cast<const T*>(this);
		}

		//-----------------------------------------------------------------------------
		// Access operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline T& Matrix4<T>::operator()( unsigned int row, unsigned int column )
		{
			assert( row < 4  &&  column < 4 );
			return m[ row ][ column ];
		}

		//-----------------------------------------------------------------------------
		// Const access operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline T Matrix4<T>::operator()( unsigned int row, unsigned int column ) const
		{
			assert( row < 4  &&  column < 4 );
			return m[ row ][ column ];
		}

		//-----------------------------------------------------------------------------
		// Equal to
		//-----------------------------------------------------------------------------
		template < class T >
		inline bool Matrix4<T>::operator == ( const Matrix4<T>& mat ) const
		{
			return 0 == memcmp( this, &mat, sizeof( Matrix4<T> ) );
		}

		//-----------------------------------------------------------------------------
		// Not Equal to
		//-----------------------------------------------------------------------------
		template < class T >
		inline bool Matrix4<T>::operator != ( const Matrix4<T>& mat ) const
		{
			return 0 != memcmp( this, &mat, sizeof( Matrix4<T> ) );
		}

		//-----------------------------------------------------------------------------
		// Unary minus
		//-----------------------------------------------------------------------------
		template < class T >
		inline const Matrix4<T> Matrix4<T>::operator - () const 
		{
			return Matrix4<T>(	-m00, -m01, -m02, -m03,
								-m10, -m11, -m12, -m13,
								-m20, -m21, -m22, -m23,
								-m30, -m31, -m32, -m33);
		}

		//-----------------------------------------------------------------------------
		// Addition operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline const Matrix4<T> Matrix4<T>::operator + ( const Matrix3<T>& mat ) const
		{
			return Matrix4<T>( m00 + mat.m00, m01 + mat.m01, m02 + mat.m02, m03,
							  m10 + mat.m10, m11 + mat.m11, m12 + mat.m12, m13,
							  m20 + mat.m20, m21 + mat.m21, m22 + mat.m22, m23,
							  m30,			 m31,			m32,		   m33);
		}
		
		template < class T >
		inline const Matrix4<T> Matrix4<T>::operator + ( const Matrix4<T>& mat ) const
		{
			Matrix4<T> ans;
			ans.Add( *this, mat );
			return ans;
		}

		//-----------------------------------------------------------------------------
		// Matrix addition
		//-----------------------------------------------------------------------------
		template < class T >
		inline void Matrix4<T>::Add( const Matrix4<T>& matA, const Matrix4<T>& matB )
		{
			m00 = matA.m00 + matB.m00; m01 = matA.m01 + matB.m01; m02 = matA.m02 + matB.m02; m03 = matA.m03 + matB.m03;
			m10 = matA.m10 + matB.m10; m11 = matA.m11 + matB.m11; m12 = matA.m12 + matB.m12; m13 = matA.m13 + matB.m13;
			m20 = matA.m20 + matB.m20; m21 = matA.m21 + matB.m21; m22 = matA.m22 + matB.m22; m23 = matA.m23 + matB.m23;
			m30 = matA.m30 + matB.m30; m31 = matA.m31 + matB.m31; m32 = matA.m32 + matB.m32; m33 = matA.m33 + matB.m33;
			
		}

		//-----------------------------------------------------------------------------
		// Addition Assignment
		//-----------------------------------------------------------------------------
		template < class T >
		inline Matrix4<T>& Matrix4<T>::operator += ( const Matrix3<T>& mat )
		{
			m00 += mat.m00 ; m01 += mat.m01 ; m02 += mat.m02 ; 
			m10 += mat.m10 ; m11 += mat.m11 ; m12 += mat.m12 ; 
			m20 += mat.m20 ; m21 += mat.m21 ; m22 += mat.m22 ; 
			return *this;
		}
		
		template < class T >
		inline Matrix4<T>& Matrix4<T>::operator += ( const Matrix4<T>& mat )
		{
			m00 += mat.m00 ; m01 += mat.m01 ; m02 += mat.m02 ; m03 += mat.m03 ;
			m10 += mat.m10 ; m11 += mat.m11 ; m12 += mat.m12 ; m13 += mat.m13 ;
			m20 += mat.m20 ; m21 += mat.m21 ; m22 += mat.m22 ; m23 += mat.m23 ;
			m30 += mat.m30 ; m31 += mat.m31 ; m32 += mat.m32 ; m33 += mat.m33 ;
			return *this;
		}

		//-----------------------------------------------------------------------------
		// Subtraction 
		//-----------------------------------------------------------------------------
		template < class T > 
		inline const Matrix4<T> Matrix4<T>::operator - ( const Matrix3<T>& mat ) const
		{
			return Matrix4<T>( m00 - mat.m00, m01 - mat.m01, m02 - mat.m02, m03,
				 			   m10 - mat.m10, m11 - mat.m11, m12 - mat.m12, m13,
							   m20 - mat.m20, m21 - mat.m21, m22 - mat.m22, m23,
							   m30, m31, m32, m33);
		}
		
		template < class T >
		inline const Matrix4<T> Matrix4<T>::operator - ( const Matrix4<T>& mat ) const
		{
			Matrix4<T> ans;
			ans.Subtract( *this, mat );
			return ans;
		}

		//-----------------------------------------------------------------------------
		// Matrix subtraction
		//-----------------------------------------------------------------------------
		template < class T >
		inline void Matrix4<T>::Subtract( const Matrix4<T>& matA, const Matrix4<T>& matB )
		{
			m00 = matA.m00 - matB.m00; m01 = matA.m01 - matB.m01; m02 = matA.m02 - matB.m02; m03 = matA.m03 - matB.m03;
			m10 = matA.m10 - matB.m10; m11 = matA.m11 - matB.m11; m12 = matA.m12 - matB.m12; m13 = matA.m13 - matB.m13;
			m20 = matA.m20 - matB.m20; m21 = matA.m21 - matB.m21; m22 = matA.m22 - matB.m22; m23 = matA.m23 - matB.m23;
			m30 = matA.m30 - matB.m30; m31 = matA.m31 - matB.m31; m32 = matA.m32 - matB.m32; m33 = matA.m33 - matB.m33;
		}

		//-----------------------------------------------------------------------------
		// Subtraction assignment operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline Matrix4<T>& Matrix4<T>::operator -= ( const Matrix3<T>& mat )
		{
			m00 -= mat.m00 ; m01 -= mat.m01 ; m02 -= mat.m02 ; 
			m10 -= mat.m10 ; m11 -= mat.m11 ; m12 -= mat.m12 ; 
			m20 -= mat.m20 ; m21 -= mat.m21 ; m22 -= mat.m22 ; 
			
			return *this;
		}
		
		template < class T >
		inline Matrix4<T>& Matrix4<T>::operator -= ( const Matrix4<T>& mat )
		{
			m00 -= mat.m00 ; m01 -= mat.m01 ; m02 -= mat.m02 ; m03 -= mat.m03 ;
			m10 -= mat.m10 ; m11 -= mat.m11 ; m12 -= mat.m12 ; m13 -= mat.m13 ;
			m20 -= mat.m20 ; m21 -= mat.m21 ; m22 -= mat.m22 ; m23 -= mat.m23 ;
			m30 -= mat.m30 ; m31 -= mat.m31 ; m32 -= mat.m32 ; m33 -= mat.m33 ;
			return *this;
		}

		//-----------------------------------------------------------------------------
		// Scalar multiplication operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline const Matrix4<T> Matrix4<T>::operator * ( T value ) const
		{
			return Matrix4(	m00 * value , m01 * value , m02 * value , m03 * value ,
							m10 * value , m11 * value , m12 * value , m13 * value ,
							m20 * value , m21 * value , m22 * value , m23 * value ,
							m30 * value , m31 * value , m32 * value , m33 * value);
		}

		//-----------------------------------------------------------------------------
		// Scalar multiplication Assignment
		//-----------------------------------------------------------------------------
		template < class T >
		inline Matrix4<T>& Matrix4<T>::operator *= ( T value )
		{
			m00 *= value; m01 *= value; m02 *= value; m03 *= value;
			m10 *= value; m11 *= value; m12 *= value; m13 *= value;
			m20 *= value; m21 *= value; m22 *= value; m23 *= value;
			m30 *= value; m31 *= value; m32 *= value; m33 *= value;
			return *this;
		}
		
		//-----------------------------------------------------------------------------
		// Matrix multiplication operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline Matrix4<T>& Matrix4<T>::operator *= ( const Matrix3<T>& mat )
		{
			*this = (*this) * mat;
			return *this;
		}
		
		template < class T >
		inline Matrix4<T>& Matrix4<T>::operator *= ( const Matrix4<T>& mat )
		{
			*this = (*this) * mat;
			return *this;
		}

		//-----------------------------------------------------------------------------
		// Matrix multiplication operator
		//-----------------------------------------------------------------------------
		template < class T >
		inline const Matrix4<T> Matrix4<T>::operator * ( const Matrix3<T>& mat ) const
		{
			return Matrix4<T>( m00 * mat.m00, m01 * mat.m01, m02 * mat.m02, m03,
				 			   m10 * mat.m10, m11 * mat.m11, m12 * mat.m12, m13,
							   m20 * mat.m20, m21 * mat.m21, m22 * mat.m22, m23,
							   m30, m31, m32, m33);
		}
		
		template < class T >
		inline const Matrix4<T> Matrix4<T>::operator * ( const Matrix4<T>& mat ) const
		{
			Matrix4<T> ans;
			ans.Multiply( *this, mat );
			return ans;
		}

		//-----------------------------------------------------------------------------
		// Matrix multiplication
		//-----------------------------------------------------------------------------
		template < class T >
		inline void Matrix4<T>::Multiply( const Matrix4<T>& matA, const Matrix4<T>& matB )
		{
			m00 = matA.m00 * matB.m00 + matA.m01 * matB.m10 + matA.m02 * matB.m20 + matA.m03 * matB.m30;
			m01 = matA.m00 * matB.m01 + matA.m01 * matB.m11 + matA.m02 * matB.m21 + matA.m03 * matB.m31;
			m02 = matA.m00 * matB.m02 + matA.m01 * matB.m12 + matA.m02 * matB.m22 + matA.m03 * matB.m32;
			m03 = matA.m00 * matB.m03 + matA.m01 * matB.m13 + matA.m02 * matB.m23 + matA.m03 * matB.m33;
			m10 = matA.m10 * matB.m00 + matA.m11 * matB.m10 + matA.m12 * matB.m20 + matA.m13 * matB.m30;
			m11 = matA.m10 * matB.m01 + matA.m11 * matB.m11 + matA.m12 * matB.m21 + matA.m13 * matB.m31;
			m12 = matA.m10 * matB.m02 + matA.m11 * matB.m12 + matA.m12 * matB.m22 + matA.m13 * matB.m32;
			m13 = matA.m10 * matB.m03 + matA.m11 * matB.m13 + matA.m12 * matB.m23 + matA.m13 * matB.m33;
			m20 = matA.m20 * matB.m00 + matA.m21 * matB.m10 + matA.m22 * matB.m20 + matA.m23 * matB.m30;
			m21 = matA.m20 * matB.m01 + matA.m21 * matB.m11 + matA.m22 * matB.m21 + matA.m23 * matB.m31;
			m22 = matA.m20 * matB.m02 + matA.m21 * matB.m12 + matA.m22 * matB.m22 + matA.m23 * matB.m32;
			m23 = matA.m20 * matB.m03 + matA.m21 * matB.m13 + matA.m22 * matB.m23 + matA.m23 * matB.m33;
			m30 = matA.m30 * matB.m00 + matA.m31 * matB.m10 + matA.m32 * matB.m20 + matA.m33 * matB.m30;
			m31 = matA.m30 * matB.m01 + matA.m31 * matB.m11 + matA.m32 * matB.m21 + matA.m33 * matB.m31;
			m32 = matA.m30 * matB.m02 + matA.m31 * matB.m12 + matA.m32 * matB.m22 + matA.m33 * matB.m32;
			m33 = matA.m30 * matB.m03 + matA.m31 * matB.m13 + matA.m32 * matB.m23 + matA.m33 * matB.m33;
		}


		//-----------------------------------------------------------------------------
	// Set the matrix for anticlockwise rotation about the x axis
	//-----------------------------------------------------------------------------
	template < class T >
	inline void Matrix4<T>::RotateX( T angle )
	{
		const T cosAngle = cosf( angle );
		const T sinAngle = sinf( angle );
		m00 = 1.0f; m01 =  0.0f;     m02 = 0.0f;     m03 = 0.0f;
		m10 = 0.0f; m11 =  cosAngle; m12 = sinAngle; m13 = 0.0f;
		m20 = 0.0f; m21 = -sinAngle; m22 = cosAngle; m23 = 0.0f;
		m30 = 0.0f; m31 =  0.0f;     m32 = 0.0f;     m33 = 1.0f;
	}

	//-----------------------------------------------------------------------------
	// Set the matrix for anticlockwise rotation about the y axis
	//-----------------------------------------------------------------------------
	template < class T >
	inline void Matrix4<T>::RotateY( T angle )
	{
		const T cosAngle = cosf( angle );
		const T sinAngle = sinf( angle );
		m00 = cosAngle; m01 =  0.0f;	m02 = -sinAngle; m03 = 0.0f;
		m10 = 0.0f;		m11 =  1.0f;	m12 = 0.0f;		 m13 = 0.0f;
		m20 = sinAngle; m21 =  0.0f;	m22 = cosAngle;  m23 = 0.0f;
		m30 = 0.0f;		m31 =  0.0f;    m32 = 0.0f;      m33 = 1.0f;
	}

	//-----------------------------------------------------------------------------
	// Set the matrix for anticlockwise rotation about the z axis
	//-----------------------------------------------------------------------------
	template < class T >
	inline void Matrix4<T>::RotateZ( T angle )
	{
		const T cosAngle = cosf( angle );
		const T sinAngle = sinf( angle );
		m00 =  cosAngle; m01 = sinAngle; m02 = 0.0f; m03 = 0.0f;
		m10 = -sinAngle; m11 = cosAngle; m12 = 0.0f; m13 = 0.0f;
		m20 =  0.0f;     m21 = 0.0f;     m22 = 1.0f; m23 = 0.0f;	
		m30 =  0.0f;     m31 = 0.0f;     m32 = 0.0f; m33 = 1.0f;
	}

	//-----------------------------------------------------------------------------
	// Rotation on the ZXY axis
	//-----------------------------------------------------------------------------
	template < class T >
	inline void	Matrix4<T>::RotateZXY( const Vector3<T>& angles )
	{
		Matrix4<T> xRotation, yRotation, zRotation;
		xRotation.RotateX(angles.x);
		yRotation.RotateY(angles.y);
		zRotation.RotateZ(angles.z);
		*this = zRotation * xRotation * yRotation;
	}

	//-----------------------------------------------------------------------------
	// Rotation on the ZXY axis with translation
	//-----------------------------------------------------------------------------
	template < class T >
	inline void	Matrix4<T>::RotateZXYTranslation( const Vector3<T>& angles, const Vector3<T>& vec )
	{
		RotateZXY( angles );
		m30 = vec.x; m31 = vec.y; m32 = vec.z;
	}


	//-----------------------------------------------------------------------------
	// Set the matrix
	//-----------------------------------------------------------------------------
	template < class T >
	inline void Matrix4<T>::Scale( const Vector3<T>& vec )
	{
		m00 =  vec.x;	m01 = 0.0f;		m02 = 0.0f;		m03 = 0.0f;
		m10 =  0.0f;	m11 = vec.y;	m12 = 0.0f;		m13 = 0.0f;
		m20 =  0.0f;    m21 = 0.0f;     m22 = vec.z;	m23 = 0.0f;	
		m30 =  0.0f;    m31 = 0.0f;     m32 = 0.0f;		m33 = 1.0f;
	}

	//-----------------------------------------------------------------------------
	// Set the matrix
	//-----------------------------------------------------------------------------
	template < class T >
	inline void Matrix4<T>::Scale( T value )
	{
		Scale( Vector3<T>( value, value, value ) );
	}

	//-----------------------------------------------------------------------------
	// Translate vector
	//-----------------------------------------------------------------------------
	template < class T >
	inline void	Matrix4<T>::Translate( const Vector3<T>& vec )
	{
		m00 = 1.0f;  m01 = 0.0f;  m02 = 0.0f;  m03 = 0.0f;
		m10 = 0.0f;  m11 = 1.0f;  m12 = 0.0f;  m13 = 0.0f;
		m20 = 0.0f;  m21 = 0.0f;  m22 = 1.0f;  m23 = 0.0f;
		m30 = vec.x; m31 = vec.y; m32 = vec.z; m33 = 1.0f;
	}

	//-----------------------------------------------------------------------------
	// Get Transpose matrix
	//-----------------------------------------------------------------------------
	template < class T >
	inline Matrix4<T> Matrix4<T>::GetTranspose() const
	{
		Matrix4<T> mat;
		mat.m00 = m00; mat.m01 = m10; mat.m02 = m20; mat.m03 = m30;
		mat.m10 = m01; mat.m11 = m11; mat.m12 = m21; mat.m13 = m31;
		mat.m20 = m02; mat.m21 = m12; mat.m22 = m22; mat.m23 = m32;
		mat.m30 = m03; mat.m31 = m13; mat.m32 = m23; mat.m33 = m33;

		return mat;
	}

	//-----------------------------------------------------------------------------
	// Transpose matrix
	//-----------------------------------------------------------------------------
	template < class T >
	inline void Matrix4<T>::Transpose()
	{
		T value;
		value = m01; m01 = m10; m10 = value;
		value = m02; m02 = m20; m20 = value;
		value = m12; m12 = m21; m21 = value;	
		value = m03; m03 = m30; m30 = value;	
		value = m13; m13 = m31; m31 = value;
		value = m23; m23 = m32; m32 = value;
	}

		

	}
}


#endif